var ImageLibrary = new function () 
{
  this.WIDTH = 80;
  this.HEIGHT = 80;
  this.PADDING = 4;
  this.Images = [];
  
  this.doBlur = function(data, width, height)
  {
    var newData = {data:[], dataSize:width*height};
    for (var y=0; y<height; y++)
    {
      for (var x=0; x<width; x++)
      {
        var xl = Math.max(0,x-1);
        var xr = Math.min(width-1,x+1);
        var yl = Math.max(0,y-1);
        var yr = Math.min(height-1,y+1);
        
        var index = y*width+x;
        
        newData.data[index] = Math.floor((
          data[index] + 
          data[y*width+xl] +
          data[y*width+xr] +
          data[yl*width+x] +
          data[yr*width+x] )/5);
      }
    }
    return newData;
  }
  this.splitRGBA = function(data, dataSize)
  {
   var newData = {red:[], green:[],blue:[],alpha:[],dataSize:dataSize};
    for (var i=0; i<dataSize; i++)
    {
      newData.red[i] = data[i*4];
      newData.green[i] = data[i*4+1];
      newData.blue[i] = data[i*4+2];
      newData.alpha[i] = 255;
    }
    return newData;
  }
  this.getRGBA = function(red,green,blue, dataSize)
  {
    var newData = {data:[], dataSize:dataSize*4};
    for (var i=0; i<dataSize; i++)
    {
      newData.data[i*4] = red[i];
      newData.data[i*4+1] = green[i];
      newData.data[i*4+2] = blue[i];
      newData.data[i*4+3] = 255;
    }
    return newData;
  }
  function rgbToHsv(red,green,blue)
  {
    var hsv = {h:0,s:0,v:0};
    var min = Math.min(Math.min(red, green), blue);
    var max = Math.max(Math.max(red, green), blue);

    hsv.v = max;            
    var delta = max - min;
    if( max > 0 ) 
    {
        hsv.s = Math.floor((delta / max)*255);                 
    } 
    else 
    {
        hsv.s = 0;
        hsv.h = 0;                
        return hsv;// fail
    }
    
    if( red >= max )   
    {
        hsv.h = ( green - blue ) / delta;  
    }
    else if( green >= max )
    {
        hsv.h = 2 + ( blue - red ) / delta;
    }
    else
    {
        hsv.h = 4 + ( red - green ) / delta; 
    }

    hsv.h /= 6.0; 

    if( hsv.h < 0.0 )
    {
        hsv.h += 1.0;
    }
    hsv.h = Math.floor(hsv.h*255);
    return hsv;
    
  }
  this.getHSV = function(data, dataSize)
  {
    var newData = {h:[],s:[],v:[], dataSize:dataSize};
    for (var i=0; i<dataSize; i++)
    {
      var hsv = rgbToHsv(data[i*4],data[i*4+1] ,data[i*4+2]);
      
      newData.h[i] = hsv.h;
      newData.s[i] = hsv.s;
      newData.v[i] = hsv.v;
    }
    return newData;
  }
  this.getGrayScaled = function(red,green,blue, dataSize)
  {
    var newData = {data:[], dataSize: dataSize};
    for (var i=0; i<dataSize; i++)
    {
      var gray = Math.floor(Math.min(255, red[i]*0.222 + green[i]*0.707 + blue[i]*0.071));
      newData.data[i] = gray;
    }
    return newData;
  }

  this.getHistogram = function(data, dataSize)
  {
    var newData = {data:[], dataSize:256};
    for (var i=0; i<256; i++)
    {
      newData.data[i] = 0;
    }
    for (var i=0; i<dataSize; i++)
    {
      var index = Math.max(0,Math.min(255, data[i]));
      newData.data[index] = newData.data[index]+1;
    }
    return newData;
  }
  this.createImageData = function(ctx, data, width, height)
  {
    var imgdata = ctx.createImageData(width, height);
    for (var i = 0; i < width*height*4; i++) 
    {
        imgdata.data[i] = data[i];
    }
    return imgdata;
  }
  
  this.getMergeClose = function(hData, hDataSize, dData, dDataSize, num)
  {
    var newData = {data:[], dataSize:dDataSize};
    for (var i=0; i<dDataSize; i++)
    {
      newData.data[i] = 255;
    }
    
    var maxCount = dDataSize/num;
    var currCount = 0;
    var value = 0;
    var startIndex = 0;
    for (var i=0; i<hDataSize+1; i++)
    {
      if (i==hDataSize) // last
      {
        maxCount = 0;
      }
      else
      {
        currCount = currCount + hData[i];
        value = value + i*hData[i];
      }
      if (currCount > maxCount)
      {
        var newVal = Math.floor(value/currCount);
        for (var j=0; j<dDataSize; j++)
        {
          if (dData[j] >= startIndex && dData[j] <= i)
          {
            newData.data[j] = newVal;
          }
        }
        currCount = 0;
        value = 0;
        startIndex = i+1;
      }
    }
    return newData;
  }
  this.processBlur = function(canvas)
  {
    var ctx = canvas.getContext("2d");
    var imgData = ctx.getImageData(0,0,this.WIDTH,this.HEIGHT);
    var split = this.splitRGBA(imgData.data, imgData.width*imgData.height);
    split.red = this.doBlur(split.red, imgData.width, imgData.height).data;
    split.green = this.doBlur(split.green,  imgData.width, imgData.height).data;
    split.blue = this.doBlur(split.blue,  imgData.width, imgData.height).data;
    var rgba = this.getRGBA(split.red,split.green,split.blue, split.dataSize);
    
    var newImg = this.createImageData(ctx, rgba.data, imgData.width, imgData.height);
    ctx.putImageData(newImg,0,0);
  }
  this.processGray = function(canvas)
  {
    var ctx = canvas.getContext("2d");
    var imgData = ctx.getImageData(0,0,this.WIDTH,this.HEIGHT);
    var split = this.splitRGBA(imgData.data, imgData.width*imgData.height);
    var pGray = this.getGrayScaled(split.red, split.green, split.blue,  split.dataSize);
    var rgba = this.getRGBA(pGray.data,pGray.data,pGray.data, pGray.dataSize);
    
    var newImg = this.createImageData(ctx, rgba.data, imgData.width, imgData.height);
    ctx.putImageData(newImg,0,0);
  }
  this.processToon = function(canvas)
  {
    var ctx = canvas.getContext("2d");
    var imgData = ctx.getImageData(0,0,this.WIDTH,this.HEIGHT);
    var split = this.splitRGBA(imgData.data, imgData.width*imgData.height);
    
    var pHistogram = this.getHistogram(split.red, split.dataSize);
    
    // merge values against histogram
    var pMergeClose = this.getMergeClose(pHistogram.data, pHistogram.dataSize,split.red, split.dataSize,8);
    
    var rgba = this.getRGBA(pMergeClose.data,pMergeClose.data,pMergeClose.data, pMergeClose.dataSize);
    
    var newImg = this.createImageData(ctx, rgba.data, imgData.width, imgData.height);
    ctx.putImageData(newImg,0,0);
  }
  this.process = function(canvas)
  {
    var ctx = canvas.getContext("2d");
    var imgData = ctx.getImageData(0,0,this.WIDTH,this.HEIGHT);
    var split = this.splitRGBA(imgData.data, imgData.width*imgData.height);
    
    for (var i=0; i<4; i++)
    {
      split.red = this.doBlur(split.red, imgData.width, imgData.height).data;
      split.green = this.doBlur(split.green,  imgData.width, imgData.height).data;
      split.blue = this.doBlur(split.blue,  imgData.width, imgData.height).data;
    }
   // var rgba = this.getRGBA(split.red, split.green, split.blue,  split.dataSize);
    
    var pGray = this.getGrayScaled(split.red, split.green, split.blue,  split.dataSize);
    
    var pHistogram = this.getHistogram(pGray.data, pGray.dataSize);
    
    // merge values against histogram
    var pMergeClose = this.getMergeClose(pHistogram.data, pHistogram.dataSize,pGray.data, pGray.dataSize,8);
    
    var rgba = this.getRGBA(pMergeClose.data,pMergeClose.data,pMergeClose.data, pMergeClose.dataSize);
    
    
    var newImg = this.createImageData(ctx, rgba.data, imgData.width, imgData.height);
    ctx.putImageData(newImg,0,0);
    
    var image = new Image;
    image.src = canvas.toDataURL();
    return image;
  }
  this.set = function(index, img)
  {
    this.Images[index] = img;
  }
  this.save = function(index)
  {
    localStorage.setItem("img"+index, this.Images[index].src);
  }
  this.load = function(index)
  {
    var value = localStorage.getItem("img"+index);
    if (value)
    {
      var img = new Image;
      img.src = value;
      this.Images[index] = img;
    }
  }
	this.draw = function(canvas, selected, img, imgData)
  {
    var ctx = canvas.getContext("2d");
    ctx.fillStyle = "#898389";
    if (selected)
    {
      ctx.fillStyle = "#FFFFFF";
    }
    ctx.fillRect(imgData.x,imgData.y, imgData.w, imgData.h);
    if (img)
    {
      ctx.drawImage(img, imgData.x+this.PADDING,imgData.y+this.PADDING,imgData.w-this.PADDING*2, imgData.h-this.PADDING*2);
    }
    else
    {
      ctx.fillStyle = "#234234";
      ctx.fillRect(imgData.x+this.PADDING,imgData.y+this.PADDING,imgData.w-this.PADDING*2, imgData.h-this.PADDING*2);
    }
    
  }
}

